﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.Service.Contract;
using CPPEI.Coolzon.ServiceProxy;
using CPPEI.Coolzon.ServiceProxy.MainServiceRef;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CPPEI.Coolzon.UI.Views
{
    public class ReconnectThread
    {
        private static object s_lockObj = new object();

        private static Thread s_thread;
        private static bool s_isRunning = false;
        private static long s_latestTicks = 0;
        private static EventWaitHandle s_waitHandle;

        /// <summary>
        /// 启动切换主服务器的线程。
        /// 启动线程之后，会向当前可用的服务发送切换为主服务器的指令。
        /// 当指令成功执行之后，线程关闭。
        /// </summary>
        public static void Start()
        {
            lock (s_lockObj)
            {
                if (s_thread == null && s_isRunning == false)
                {
                    s_waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);

                    s_thread = new Thread(Running);
                    s_thread.Name = "ReconnectThread";
                    s_isRunning = true;
                    Logger.DebugToTag(Library.LogTag, "重连服务线程启动");
                    s_thread.Start();
                }
            }
        }

        /// <summary>
        /// 关闭切换主服务的线程
        /// </summary>
        public static void Stop()
        {
            lock (s_lockObj)
            {
                if (s_thread != null && s_isRunning)
                {
                    s_isRunning = false;
                    // 等待线程结束
                    s_waitHandle.WaitOne();
                    Logger.DebugToTag(Library.LogTag, "重连服务线程停止");
                }
            }
        }

        private static void Running()
        {
            Logger.DebugToTag(Library.LogTag, "重连服务线程运行开始");
            while (s_isRunning)
            {
                if (DateTime.Now.Ticks - s_latestTicks > TimeSpan.FromSeconds(5).Ticks)
                {
                    Reconnecting();
                    s_latestTicks = DateTime.Now.Ticks;
                }

                Thread.Sleep(100);
            }

            Logger.DebugToTag(Library.LogTag, "重连服务线程运行结束");

            s_waitHandle.Set();

            s_isRunning = false;
            s_thread = null;
        }

        /// <summary>
        /// 检查代理中是否有网络断开的终端，如果有那么进行重新连接
        /// </summary>
        private static void Reconnecting()
        {
            for (int index = 0; index < ClientProxyManager.Instance.Proxies.Count; index++)
            {
                #region 获取proxy，检测并发送请求
                MainServiceProxy proxy = ClientProxyManager.Instance.Proxies[index];

                if(proxy.State ==  ServiceProxyState.Reconnecting
                    && proxy.Client.State != System.ServiceModel.CommunicationState.Opened)
                {
                    Logger.ErrorToTag(Library.LogTag, "服务器代理ip:{0},Port{1}的State:{2},但是Client状态不是Opened，设置为Disconnected", proxy.IP, proxy.Port, proxy.State);
                    proxy.GoToDisconnectState();
                }

                if (proxy.State != ServiceProxyState.Connected
                    && proxy.State != ServiceProxyState.Reconnecting
                    && proxy.State != ServiceProxyState.ReconnectFinished)
                {
                    // 当proxy的状态处于Disconnected发送重新连接的请求
                    RenderView renderView = UIContext.Current.RenderView as RenderView;

                    ReqReconnectData reconnectData = new ReqReconnectData();
                    reconnectData.UserAccount = UIContext.Current.UserAccount;
                    reconnectData.UserIdentity = UIContext.Current.UserIdentity;
                    reconnectData.DomainId = UIContext.Current.ControlDomainId;
                    reconnectData.DomainCaption = UIContext.Current.ControlDomainId;
                    reconnectData.SolutionName = UIContext.Current.SolutionName;
                    reconnectData.SolutionCaption = UIContext.Current.SolutionName;
                    reconnectData.AppType = UIContext.Current.AppType;
                    reconnectData.OperatorIdentity = UIContext.Current.OperatorIdentity;
                    if (UIContext.Current.IsUnderControl)
                    {
                        reconnectData.ControlState = ControlState.UnderControl;
                    }
                    else
                    {
                        reconnectData.ControlState = ControlState.OutOfControl;
                    }
                    if(renderView != null)
                    {
                        Coolzon.ViewState.ViewState viewState = renderView.GetViewState();
                        reconnectData.ViewStateAge = viewState.Age;
                        reconnectData.ViewStateToken = Coolzon.ViewState.ViewState.ToToken(viewState);
                    }

                    reconnectData.MainServerIP = UIContext.Current.MainServerIP;
                    reconnectData.MainServerPort = UIContext.Current.MainServerPort;

                    // 发送重新连接的请求
                    Request request = RequestUtil.BuildRequest(UIContext.Current.ControlDomainId,
                        UIContext.Current.UserIdentity,
                        SCENARIO.CONNECT,
                        COMMAND.CONNECT.RECONNECT,
                        REQUEST_MODE.SELF,
                        reconnectData);

                    try
                    {
                        //连接无效，重现建立连接发生请求
                        if(proxy.State == ServiceProxyState.Disconnected)
                        {
                            if(proxy.Reconnect())
                            {
                                Logger.ErrorToTag(Library.LogTag, "向服务器ip:{0},Port{1}发送重连请求State:{2}", proxy.IP, proxy.Port, proxy.State);
                                proxy.Client.SendRequest(request);
                                proxy.State = ServiceProxyState.Reconnecting;
                            }
                        }
                        //如果重连失败，则不重现建立连接，再次发送请求
                        else if(proxy.State == ServiceProxyState.ReconnectFailure)
                        {
                            Logger.ErrorToTag(Library.LogTag, "向服务器ip:{0},Port{1}发送重连请求State:{2}", proxy.IP, proxy.Port, proxy.State);
                            proxy.Client.SendRequest(request);
                            proxy.State = ServiceProxyState.Reconnecting;
                        }
                    }
                    catch(Exception ex)
                    {
                        proxy.State = ServiceProxyState.Disconnected;
                        Logger.ErrorToTag(Library.LogTag, "重连服务器出错ip:{0},Port{1},ex:{2}", proxy.IP, proxy.Port, ex);
                    }
                }
                #endregion
            }
        }
    }
}